package com.neusoft.yiyang.task.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.neusoft.yiyang.common.entity.care.CareItem;
import com.neusoft.yiyang.common.entity.care.CustomerCareItem;
import com.neusoft.yiyang.common.entity.customer.Customer;
import com.neusoft.yiyang.common.entity.medical.DrugDict;
import com.neusoft.yiyang.common.entity.medical.MedicationOrder;
import com.neusoft.yiyang.common.entity.medical.MedicationOrderRecord;
import com.neusoft.yiyang.common.entity.task.CareTask;
import com.neusoft.yiyang.common.enums.ExecCycle;
import com.neusoft.yiyang.common.enums.ExecutionStatus;
import com.neusoft.yiyang.common.enums.TaskStatus;
import com.neusoft.yiyang.common.enums.TaskType;
import com.neusoft.yiyang.common.exception.BusinessException;
import com.neusoft.yiyang.task.client.*;
import com.neusoft.yiyang.task.mapper.CareTaskMapper;
import com.neusoft.yiyang.task.service.TaskService;
import feign.FeignException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;

@Service
public class TaskServiceImpl implements TaskService {

    private static final Logger logger = LoggerFactory.getLogger(TaskServiceImpl.class);

    @Autowired
    private CareTaskMapper careTaskMapper;

    @Autowired
    private CustomerClient customerClient;

    @Autowired
    private CareClient careClient;

    @Autowired
    private MedicationOrderClient medicationOrderClient;

    @Autowired
    private MedicationOrderRecordClient medicationOrderRecordClient;

    @Autowired
    private DrugClient drugClient;

    @Override
    public void createTask(CareTask careTask) {
        careTaskMapper.insert(careTask);
    }

    @Override
    public CareTask getTaskById(Integer careTaskId) {
        return careTaskMapper.selectById(careTaskId);
    }

    @Override
    public List<CareTask> getAllTasks() {
        return careTaskMapper.selectList(null);
    }

    @Override
    public List<CareTask> getTasksByCustomerId(Integer customerId) {
        return careTaskMapper.selectByCustomerId(customerId);
    }

    @Override
    public List<CareTask> getTasksByCaretakerId(Integer caretakerId) {
        return careTaskMapper.selectByCaretakerId(caretakerId);
    }

    @Override
    public void updateTask(CareTask careTask) {
        careTaskMapper.updateById(careTask);
    }

    @Override
    public void deleteTask(Integer careTaskId) {
        careTaskMapper.deleteById(careTaskId);
    }

    @Override
    @Transactional
    public void handleCustomerUpdateForNursingTasks(Integer customerId) {
        logger.info("处理客户 {} 信息变更，重新生成当天护理任务", customerId);
        // 1. 获取客户信息
        Customer customer = customerClient.getCustomerById(customerId);
        // 2. 检查客户是否有效（护理老人且有护工）
        if (customer == null || customer.getCustomerType() != 1 || customer.getCaretakerId() == null) {
            logger.info("客户 {} 不是护理老人或未分配护工，删除当天未完成的护理任务", customerId);
            deletePendingNursingTasksForCustomerToday(customerId);
            return;
        }
        // 3. 重新生成当天护理任务
        generateNursingTasksForCustomer(customerId);
    }

    @Override
    @Transactional
    public void generateNursingTasksForCustomer(Integer customerId) {
        logger.info("为客户 {} 生成当天护理任务", customerId);

        // 1. 获取客户信息
        Customer customer = customerClient.getCustomerById(customerId);
        if (customer == null) {
            throw new BusinessException(5001, "客户不存在: " + customerId);
        }

        Integer caretakerId = customer.getCaretakerId();
        if (caretakerId == null) {
            throw new BusinessException(5002, "客户未分配护工: " + customerId);
        }

        // 2. 删除该客户当天已经生成但未完成的护理任务
        deletePendingNursingTasksForCustomerToday(customerId);

        // 3. 获取客户有效的护理项目
        List<CustomerCareItem> careItems = careClient.getCustomerCareItemsByCustomerId(customerId);
        if (careItems == null || careItems.isEmpty()) {
            logger.info("客户 {} 没有有效的护理项目", customerId);
            return;
        }
        // 4. 为每个护理项目生成当天护理任务
        for (CustomerCareItem careItem : careItems) {
            // 获取护理项目详情
            CareItem item = careClient.getCareItemById(careItem.getCareItemId());
            if (item == null || item.getStatus() != 1) {
                logger.warn("护理项目 {} 不存在或已禁用", careItem.getCareItemId());
                continue;
            }
            // 检查执行周期，判断今天是否需要执行
            if (!isTodayExecutionRequiredForNursing(item.getExecCycle())) {
                continue;
            }
            // 创建护理任务
            CareTask task = new CareTask();
            task.setCustomerId(customerId);
            task.setTaskType(TaskType.nursing);
            task.setRefId(item.getCareItemId());
            task.setCaretakerId(caretakerId);
            // 计划执行时间设为当天（具体时间不重要）
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            calendar.set(Calendar.MILLISECOND, 0);
            task.setScheduledTime(calendar.getTime());
            task.setStatus(TaskStatus.pending);
            task.setQuantity(1.0); // 默认执行量为1次
            careTaskMapper.insert(task);
            logger.debug("为客户 {} 创建护理任务: 项目 {}", customerId, item.getItemName());
        }

        logger.info("为客户 {} 生成 {} 个护理任务", customerId, careItems.size());
    }

    @Override
    @Transactional
    public void updateNursingTaskStatus(Integer taskId, TaskStatus status,
                                        Integer caretakerId, Integer quantity, String feedback,
                                        MultipartFile file) {
        // 查询护理任务
        CareTask task = careTaskMapper.selectById(taskId);
        if (task == null) {
            throw new BusinessException(5003, "护理任务不存在，ID: " + taskId);
        }
        if (task.getTaskType() != TaskType.nursing) {
            throw new BusinessException(5004, "只能更新护理任务状态");
        }

        // 若状态为"已完成"，则调用care-service创建护理记录并更新使用次数
        if (TaskStatus.completed.equals(status)) {
            if (caretakerId == null) {
                throw new BusinessException(5005, "完成护理任务必须指定护工ID");
            }
            if (quantity == null || quantity <= 0) {
                throw new BusinessException(5006, "执行次数必须为正整数");
            }

            // 调用care-service创建护理记录并更新使用次数
            careClient.completeCareRecordWithUsageUpdate(
                    task.getCustomerId(),    // 客户ID
                    task.getRefId(),         // 护理项目ID（task.refId关联care_item_id）
                    caretakerId,             // 执行护工ID
                    quantity,                // 执行次数
                    feedback,                // 反馈
                    ExecutionStatus.normal,  // 正常完成
                    file                     // 照片
            );

            // 调用成功后，更新任务状态为"已完成"（先调用接口再更新任务）
            task.setStatus(TaskStatus.completed);
            task.setCompletedTime(new Date());
            task.setCaretakerId(caretakerId);
            careTaskMapper.updateById(task);
            logger.info("护理任务 {} 已完成，护理记录已同步至care-service", taskId);
        }
        // 若状态为"异常"，则调用care-service创建护理记录并更新使用次数为0
        else if (TaskStatus.abnormal.equals(status)) {
            try {
                if (caretakerId == null) {
                    throw new BusinessException(5007, "标记为异常必须指定护工ID");
                }
                careClient.completeCareRecordWithUsageUpdate(
                        task.getCustomerId(),     // 客户ID
                        task.getRefId(),          // 护理项目ID（task.refId关联care_item_id）
                        caretakerId,              // 执行护工ID
                        0,                        // 执行次数（标记为异常，次数为0）
                        feedback,                 // 反馈
                        ExecutionStatus.abnormal, // 异常完成
                        file                     // 照片
                );
                task.setStatus(TaskStatus.abnormal);
                task.setCompletedTime(new Date());
                task.setCaretakerId(caretakerId);
                careTaskMapper.updateById(task);
                logger.info("护理任务 {} 标记为异常，护理记录已同步至care-service", taskId);
            } catch (FeignException e) {
                logger.error("同步护理记录失败: {}", e.getMessage(), e);
                throw new BusinessException(5008, "同步护理记录失败");
            }
        } else {
            // 处理其他状态（如取消），直接更新任务状态
            task.setStatus(status);
            if (caretakerId != null) {
                task.setCaretakerId(caretakerId);
            }
            careTaskMapper.updateById(task);
        }
    }

    //利用客户Id查询对应的药品项目
    @Override
    public List<Map<String, Object>> getMedicationInfoByCustomerId(Integer customerId) {
// 获取当天零点和23:59
        LocalDate today = LocalDate.now();
        LocalDateTime start = today.atStartOfDay();
        LocalDateTime end = today.atTime(LocalTime.MAX);

        // 1. 查询当天属于该客户的“MEDICATION”类型的 care_task
        List<CareTask> careTasks = careTaskMapper.selectList(new QueryWrapper<CareTask>()
                .eq("customer_id", customerId)
                .eq("task_type", TaskType.medication)
                .between("scheduled_time", start, end)
        );

        List<Map<String, Object>> result = new ArrayList<>();

        for (CareTask task : careTasks) {
            Integer medicationOrderId = task.getRefId();

            // 2. 查询 medication_order
            MedicationOrder order = medicationOrderClient.getByMedicationOrderId(medicationOrderId);
            if (order == null) continue;

            // 3. 查询 drug_dict
            DrugDict drug = drugClient.getByDrugId(order.getDrugId());
            if (drug == null) continue;

            // 4. 封装结果
            Map<String, Object> map = new HashMap<>();
            map.put("careTasks", task);
            map.put("medicationOrders", order);
            map.put("drugDicts", drug);
            result.add(map);
        }
        System.out.println(result);
        return result;
    }

    //反馈，（修改careTask并添加medicationOrderRecord）
    @Override
    public void submitMedicationFeedback(Integer careTaskId, MedicationOrderRecord medicationOrderRecord){
        CareTask careTask = careTaskMapper.selectById(careTaskId);
        if (careTask != null) {
            careTask.setCompletedTime(medicationOrderRecord.getTakenTime());
            if(ExecutionStatus.normal.equals(medicationOrderRecord.getStatus())) {
                careTask.setStatus(TaskStatus.completed);
            } else {
                careTask.setStatus(TaskStatus.abnormal);
            }
            careTaskMapper.updateById(careTask);
        }
        medicationOrderRecord.setMedicationOrderId(careTask.getRefId());
        medicationOrderRecord.setCustomerId(careTask.getCustomerId());
        medicationOrderRecord.setCaretakerId(careTask.getCaretakerId());
        medicationOrderRecordClient.createMedicationOrderRecord(medicationOrderRecord);
    }

    @Override
    public void deleteMedicationTask(Integer customerId, Integer medicationOrderId){
        QueryWrapper<CareTask> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("customer_id", customerId).eq("ref_id",medicationOrderId);
        List<CareTask> careTasks = careTaskMapper.selectList(queryWrapper);
        for (CareTask careTask : careTasks) {
            careTaskMapper.deleteById(careTask);
        }
    }

    // ================ 私有辅助方法 ================

    /**
     * 获取客户前一天未完成的护理任务
     */
    private List<CareTask> getPendingTasksLastDay(Integer customerId) {
        Calendar cal = Calendar.getInstance();
        // 1. 计算前一天的开始时间：前一天0:00:00
        cal.add(Calendar.DAY_OF_YEAR, -1); // 切换到前一天
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        Date lastDayStart = cal.getTime();

        // 2. 计算前一天的结束时间：当天0:00:00（即前一天24:00:00）
        cal.add(Calendar.DAY_OF_YEAR, 1); // 切换回当天
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        Date lastDayEnd = cal.getTime();

        // 查询条件：前一天0:00 到 当天0:00 之间的未完成护理任务
        return careTaskMapper.selectList(new LambdaQueryWrapper<CareTask>()
                .eq(CareTask::getCustomerId, customerId)
                .eq(CareTask::getTaskType, TaskType.nursing)
                .eq(CareTask::getStatus, TaskStatus.pending)
                .ge(CareTask::getScheduledTime, lastDayStart)
                .lt(CareTask::getScheduledTime, lastDayEnd));
    }

    /**
     * 处理前一天未完成的任务（延期或标记漏执行）
     */
    private void handlePendingTasks(Integer customerId) {
        List<CareTask> pendingTasks = getPendingTasksLastDay(customerId);
        for (CareTask task : pendingTasks) {
            // 获取护理项目，判断周期
            CareItem item = careClient.getCareItemById(task.getRefId());
            if (item == null) continue;

            ExecCycle cycle = item.getExecCycle();
            if (ExecCycle.weekly.equals(cycle) || ExecCycle.monthly.equals(cycle)) {
                // 延期：原任务标记为取消，生成当日新任务
                task.setStatus(TaskStatus.cancelled);
                task.setCompletedTime(new Date());
                careTaskMapper.updateById(task);

                // 生成当日新任务
                CareTask newTask = new CareTask();
                newTask.setCustomerId(customerId);
                newTask.setTaskType(TaskType.nursing);
                newTask.setRefId(task.getRefId());
                newTask.setCaretakerId(task.getCaretakerId());
                newTask.setScheduledTime(new Date()); // 当日时间
                newTask.setStatus(TaskStatus.pending);
                careTaskMapper.insert(newTask);
                logger.info("任务{}（周期{}）延期至今日，新任务ID:{}",
                        task.getCareTaskId(), cycle, newTask.getCareTaskId());
            } else if (ExecCycle.daily.equals(cycle)) {
                // daily任务漏执行，直接标记为取消
                task.setStatus(TaskStatus.cancelled);
                careTaskMapper.updateById(task);
                logger.info("任务{}（daily）漏执行，已标记为取消", task.getCareTaskId());
            }
        }
    }

    // 定时任务：每天凌晨1点生成护理任务
    @Scheduled(cron = "0 0 1 * * ?")
    @Transactional
    public void generateDailyNursingTasks() {
        logger.info("开始生成每日护理任务");
        List<Customer> customers = customerClient.getCustomersWithCaretaker(); // 获取所有有效客户
        for (Customer customer : customers) {
            try {
                handlePendingTasks(customer.getCustomerId()); // 先处理延期
                generateNursingTasksForCustomer(customer.getCustomerId()); // 再生成当日任务
            } catch (Exception e) {
                logger.error("处理客户{}任务失败", customer.getCustomerId(), e);
            }
        }
    }

    // 删除客户当天未完成的护理任务
    private void deletePendingNursingTasksForCustomerToday(Integer customerId) {
        // 获取当天开始和结束时间
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        Date todayStart = calendar.getTime();

        calendar.add(Calendar.DAY_OF_YEAR, 1);
        Date tomorrowStart = calendar.getTime();

        // 删除当天未完成的护理任务
        int deletedCount = careTaskMapper.delete(new LambdaQueryWrapper<CareTask>()
                .eq(CareTask::getCustomerId, customerId)
                .eq(CareTask::getTaskType, TaskType.nursing)
                .eq(CareTask::getStatus, TaskStatus.pending)
                .ge(CareTask::getScheduledTime, todayStart)
                .lt(CareTask::getScheduledTime, tomorrowStart));

        logger.info("删除客户 {} 当天 {} 个未完成的护理任务", customerId, deletedCount);
    }

    // 判断今天是否需要执行（根据执行周期）
    private boolean isTodayExecutionRequiredForNursing(ExecCycle execCycle) {
        Calendar calendar = Calendar.getInstance();
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
        int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);

        switch (execCycle) {
            case daily:
                return true; // 每天都需要执行
            case weekly:
                // 周一执行（Calendar.MONDAY = 2）
                return dayOfWeek == Calendar.MONDAY;
            case monthly:
                // 每月1号执行
                return dayOfMonth == 1;
            default:
                return false;
        }
    }
}